package com.lagou.sqlSession;

import com.lagou.enums.MapperType;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;

import java.lang.reflect.*;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementid, Object... params) throws Exception {

        //将要去完成对simpleExecutor里的query方法的调用
        simpleExecutor simpleExecutor = new simpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
        List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);

        return (List<E>) list;
    }

    protected <E> List<E> selectList(MappedStatement mappedStatement, Object... params) throws Exception {
        //将要去完成对simpleExecutor里的query方法的调用
        simpleExecutor simpleExecutor = new simpleExecutor();
        List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
        return (List<E>) list;
    }




    @Override
    public <T> T selectOne(String statementid, Object... params) throws Exception {
        List<Object> objects = selectList(statementid, params);
        if(objects.size()==1){
            return (T) objects.get(0);
        }else {
            throw new RuntimeException("查询结果为空或者返回结果过多");
        }


    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        // 使用JDK动态代理来为Dao接口生成代理对象，并返回

        Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, (proxy, method, args) -> {
            // 底层都还是去执行JDBC代码 //根据不同情况，来调用selctList或者selectOne
            // 准备参数 1：statmentid :sql语句的唯一标识：namespace.id= 接口全限定名.方法名
            // 方法名：findAll
            String methodName = method.getName();
            String className = method.getDeclaringClass().getName();
            String statementId = className+"."+methodName;
            MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
            if(mappedStatement == null){ //判空校验
                //
                return null;
            }
            Type genericReturnType = method.getGenericReturnType();
            if(mappedStatement.getType() == MapperType.SELECT){
                // 准备参数2：params:args
                // 获取被调用方法的返回值类型
                // 判断是否进行了 泛型类型参数化
                if(genericReturnType instanceof ParameterizedType){
                    List<Object> objects = selectList(statementId, args);
                    return objects;
                }
                return selectOne(statementId,args);
            }
            //todo 这里可以根据新增的类型提供主键的生成,提供一个全局唯一id的生成
            // 对于编辑和删除可以提供相应的回退功能,将原数据保存
            else{
                // 判断返回值,若是返回值void则不返回
                // 若返回bool则判断返回值是否等于0
                // 否则返回int数值
                int n = edit(mappedStatement,args);
                if(method.getReturnType() == void.class){
                    //do nothing
                }else if(method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class){
                    return n > 0;
                }
                return n;
            }

        });

        return (T) proxyInstance;
    }

    @Override
    public int insert(String statementId, Object... objs) throws Exception {
        //统一调用edit，因为无论增加删除修改，数据库都是返回的受影响的行数
        return edit(statementId,objs);
    }

    @Override
    public int delete(String statementId, Object... objs) throws Exception{
        return edit(statementId,objs);
    }

    @Override
    public int update(String statementId, Object... objs) throws Exception {
        return edit(statementId,objs);
    }

    protected int edit(String statementId, Object... objs) throws Exception {
        //将要去完成对simpleExecutor里的query方法的调用
        simpleExecutor simpleExecutor = new simpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return simpleExecutor.edit(configuration, mappedStatement, objs);
    }

    protected int edit(MappedStatement mappedStatement, Object... objs) throws Exception {
        //将要去完成对simpleExecutor里的query方法的调用
        simpleExecutor simpleExecutor = new simpleExecutor();
        return simpleExecutor.edit(configuration, mappedStatement, objs);
    }

}
